{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## python 3.3 新加了yield from 语法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## yield from 使用\n",
    "\n",
    "from itertools import chain\n",
    "\n",
    "my_list = [1, 2, 3]\n",
    "my_dict = {\n",
    "    \"bobby1\": \"http://projectsedu.com\",\n",
    "    \"bobby2\": \"http://www.imooc.com\",\n",
    "}\n",
    "\n",
    "\n",
    "## yield from iterable（可迭代对象）\n",
    "def my_chain(*args, **kwargs):\n",
    "    for my_iterable in args:\n",
    "        yield from my_iterable\n",
    "        # for value in my_iterable:\n",
    "        #     yield  value\n",
    "\n",
    "## 实例1:\n",
    "# for value in my_chain(my_list, my_dict, range(5, 10)):\n",
    "#     print(value)\n",
    "\n",
    "## 实例2:\n",
    "def g1(iterable):\n",
    "    yield iterable\n",
    "def g2(iterable):\n",
    "    yield from iterable\n",
    "\n",
    "for value in g1(range(10)):\n",
    "    print(value)\n",
    "for value in g2(range(10)):\n",
    "    print(value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 1、main 调用方 g1（委托生成器）gen 自生成器\n",
    "## 2、yield from 会在调用方与子生成器之间建立一个双向通道"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 自生成器通信\n",
    "\n",
    "final_result = {}\n",
    "def sales_sum(pro_name):\n",
    "    total = 0\n",
    "    nums = []\n",
    "    while True:\n",
    "        x = yield\n",
    "        print(pro_name+\"销量: \", x)\n",
    "        if not x:\n",
    "            break\n",
    "        total += x\n",
    "        nums.append(x)\n",
    "    return total, nums\n",
    "\n",
    "## 委托生成器\n",
    "def middle(key):\n",
    "    while True:\n",
    "        final_result[key] = yield from sales_sum(key)\n",
    "        print(key+\"销量统计完成！！.\")\n",
    "\n",
    "def main():\n",
    "    data_sets = {\n",
    "        \"bobby牌面膜\": [1200, 1500, 3000],\n",
    "        \"bobby牌手机\": [28,55,98,108 ],\n",
    "        \"bobby牌大衣\": [280,560,778,70],\n",
    "    }\n",
    "    for key, data_set in data_sets.items():\n",
    "        print(\"start key:\", key)\n",
    "        m = middle(key)\n",
    "        m.send(None) # 预激middle协程\n",
    "        for value in data_set:\n",
    "            m.send(value)   # 给协程传递每一组的值\n",
    "        m.send(None)\n",
    "    print(\"final_result:\", final_result)\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## 如果没有通过yield from 拆分，则需要自行捕获StopIteration异常\n",
    "\n",
    "def sales_sum(pro_name):\n",
    "    total = 0\n",
    "    nums = []\n",
    "    while True:\n",
    "        x = yield\n",
    "        print(pro_name+\"销量: \", x)\n",
    "        if not x:\n",
    "            break\n",
    "        total += x\n",
    "        nums.append(x)\n",
    "    return total, nums\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    my_gen = sales_sum(\"bobby牌手机\")\n",
    "    my_gen.send(None)\n",
    "    my_gen.send(1200)\n",
    "    my_gen.send(1500)\n",
    "    my_gen.send(3000)\n",
    "    try:\n",
    "        my_gen.send(None)\n",
    "    except StopIteration as e:\n",
    "        result = e.value\n",
    "        print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# #pep380\n",
    "#\n",
    "# #1. RESULT = yield from EXPR可以简化成下面这样\n",
    "# #一些说明\n",
    "# \"\"\"\n",
    "# _i：子生成器，同时也是一个迭代器\n",
    "# _y：子生成器生产的值\n",
    "# _r：yield from 表达式最终的值\n",
    "# _s：调用方通过send()发送的值\n",
    "# _e：异常对象\n",
    "#\n",
    "# \"\"\"\n",
    "#\n",
    "# _i = iter(EXPR)      # EXPR是一个可迭代对象，_i其实是子生成器；\n",
    "# try:\n",
    "#     _y = next(_i)   # 预激子生成器，把产出的第一个值存在_y中；\n",
    "# except StopIteration as _e:\n",
    "#     _r = _e.value   # 如果抛出了`StopIteration`异常，那么就将异常对象的`value`属性保存到_r，这是最简单的情况的返回值；\n",
    "# else:\n",
    "#     while 1:    # 尝试执行这个循环，委托生成器会阻塞；\n",
    "#         _s = yield _y   # 生产子生成器的值，等待调用方`send()`值，发送过来的值将保存在_s中；\n",
    "#         try:\n",
    "#             _y = _i.send(_s)    # 转发_s，并且尝试向下执行；\n",
    "#         except StopIteration as _e:\n",
    "#             _r = _e.value       # 如果子生成器抛出异常，那么就获取异常对象的`value`属性存到_r，退出循环，恢复委托生成器的运行；\n",
    "#             break\n",
    "# RESULT = _r     # _r就是整个yield from表达式返回的值。\n",
    "#\n",
    "# \"\"\"\n",
    "# 1. 子生成器可能只是一个迭代器，并不是一个作为协程的生成器，所以它不支持.throw()和.close()方法；\n",
    "# 2. 如果子生成器支持.throw()和.close()方法，但是在子生成器内部，这两个方法都会抛出异常；\n",
    "# 3. 调用方让子生成器自己抛出异常\n",
    "# 4. 当调用方使用next()或者.send(None)时，都要在子生成器上调用next()函数，当调用方使用.send()发送非 None 值时，才调用子生成器的.send()方法；\n",
    "# \"\"\"\n",
    "# _i = iter(EXPR)\n",
    "# try:\n",
    "#     _y = next(_i)\n",
    "# except StopIteration as _e:\n",
    "#     _r = _e.value\n",
    "# else:\n",
    "#     while 1:\n",
    "#         try:\n",
    "#             _s = yield _y\n",
    "#         except GeneratorExit as _e:\n",
    "#             try:\n",
    "#                 _m = _i.close\n",
    "#             except AttributeError:\n",
    "#                 pass\n",
    "#             else:\n",
    "#                 _m()\n",
    "#             raise _e\n",
    "#         except BaseException as _e:\n",
    "#             _x = sys.exc_info()\n",
    "#             try:\n",
    "#                 _m = _i.throw\n",
    "#             except AttributeError:\n",
    "#                 raise _e\n",
    "#             else:\n",
    "#                 try:\n",
    "#                     _y = _m(*_x)\n",
    "#                 except StopIteration as _e:\n",
    "#                     _r = _e.value\n",
    "#                     break\n",
    "#         else:\n",
    "#             try:\n",
    "#                 if _s is None:\n",
    "#                     _y = next(_i)\n",
    "#                 else:\n",
    "#                     _y = _i.send(_s)\n",
    "#             except StopIteration as _e:\n",
    "#                 _r = _e.value\n",
    "#                 break\n",
    "# RESULT = _r\n",
    "#\n",
    "# \"\"\"\n",
    "# 看完代码，我们总结一下关键点：\n",
    "#\n",
    "# 1. 子生成器生产的值，都是直接传给调用方的；调用方通过.send()发送的值都是直接传递给子生成器的；如果发送的是 None，会调用子生成器的__next__()方法，如果不是 None，会调用子生成器的.send()方法；\n",
    "# 2. 子生成器退出的时候，最后的return EXPR，会触发一个StopIteration(EXPR)异常；\n",
    "# 3. yield from表达式的值，是子生成器终止时，传递给StopIteration异常的第一个参数；\n",
    "# 4. 如果调用的时候出现StopIteration异常，委托生成器会恢复运行，同时其他的异常会向上 \"冒泡\"；\n",
    "# 5. 传入委托生成器的异常里，除了GeneratorExit之外，其他的所有异常全部传递给子生成器的.throw()方法；如果调用.throw()的时候出现了StopIteration异常，那么就恢复委托生成器的运行，其他的异常全部向上 \"冒泡\"；\n",
    "# 6. 如果在委托生成器上调用.close()或传入GeneratorExit异常，会调用子生成器的.close()方法，没有的话就不调用。如果在调用.close()的时候抛出了异常，那么就向上 \"冒泡\"，否则的话委托生成器会抛出GeneratorExit异常。\n",
    "#\n",
    "# \"\"\""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
